package com.gitee.denger.mybatis.example.ext;

import com.gitee.denger.mybatis.example.ext.analytical.IExampleCriteriaValue;
import com.gitee.denger.mybatis.example.ext.annotation.ExampleAnalytical;
import com.gitee.denger.mybatis.example.ext.util.ClassUtils;
import com.gitee.denger.mybatis.example.ext.util.SimpleReflectionUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

/**
 * 使用tk.mybatis.mapper公共mapper时<br>
 * 简单的mybatis Example 映射<br>
 * 实现这个接口，然后在相关字段上添加其注解
 *
 * @param <Entity>  数据entity
 * @param <Example> 数据example
 * @author 登琼
 */
public interface MybatisExampleForTk<Entity, Example> extends MybatisExample<Example> {

    /**
     * 转成mybatis example
     *
     * @return 指定泛型的Example
     */
    @Override
    default Example toExample() {
        Class<?> thisClass = getClass();
        Type[] actualTypeArguments = ClassUtils.getGenericInterfaceActualTypeArguments(thisClass, MybatisExampleForTk.class);
        if (null == actualTypeArguments) {
            throw new IllegalArgumentException(String.format("%s比需填写%s的泛型", thisClass.getName(), MybatisExampleForTk.class.getSimpleName()));
        }
        Class<Entity> entityClass = (Class) actualTypeArguments[0];
        // 公共的Example tk.mybatis.mapper.entity.Example
        Class<Example> exampleClass = (Class) actualTypeArguments[1];
        Example example = ClassUtils.newInstance(exampleClass, entityClass);

        Object exampleCriteria = SimpleReflectionUtils.invokeMethod(exampleClass, example, "createCriteria");
        SimpleReflectionUtils.doWithFields(thisClass, field -> {
            //判断该字段是否存在值
            field.setAccessible(true);
            Object fieldValue = SimpleReflectionUtils.getField(field, this);
            if (null == fieldValue) {
                // 值为空，跳过
                return;
            }

            //获取注解
            Annotation[] annotations = field.getAnnotations();
            //判断注解是否为定义的路径内，是就处理
            for (Annotation annotation : annotations) {
                Class<? extends Annotation> annotationType = annotation.annotationType();
                ExampleAnalytical setValueClass = annotationType.getAnnotation(ExampleAnalytical.class);
                if (null != setValueClass) {
                    IExampleCriteriaValue exampleCriteriaValue = ExampleCriteriaValueFactory.getExampleCriteriaValue(setValueClass.value());
                    String fieldName;
                    String property = (String) SimpleReflectionUtils.invokeMethod(annotationType, annotation, "property");
                    if (null == property || "".equals(property)) {
                        fieldName = field.getName();
                    } else {
                        fieldName = property;
                    }
                    exampleCriteriaValue.setForTk(annotation, exampleCriteria, fieldName, fieldValue);
                    // 跳出for
                    break;
                }
            }
        });

        return example;
    }
}
